/*
 *  Source name     : hist_asm.s
 *  Executable name : hist_asm
 *  Code model      : Protected-mode (32-bit assembly)
 *  Version         :
 *  Created date    :
 *  Last update     :
 *  Author          :
 *  Description     : This program outputs a histogram of total scores
 *                       and a frequency distribution of grades based
 *                       on a table of raw scores.
 */

/* Declare constants */

.equiv NUM_SCORES, 5
.equiv REC_SIZE, 24
.equiv SCORE1, 8
.equiv SCORE2, 10
.equiv SCORE3, 12
.equiv SCORE4, 14
.equiv SCORE5, 16
.equiv TOTAL, 18
.equiv GRADE, 22
.equiv SCORE_RANGES_NUM, 10


.equiv MINA, 401
.equiv MINB, 301
.equiv MINC, 201
.equiv MIND, 101
.equiv MINF, 0

.equiv CR, 0x0D     /* carriage return */
.equiv LF, 0x0A     /* line feed */


.text
.global main		/* indicate program entry point */

main:
    pushl %ebp		/* Create stack frame */
    movl  %esp, %ebp	/* ebp marks our place in the stack */
    pushl %ebx		/* Save ebx, edi, & esi */
    pushl %edi
    pushl %esi

    /* begin program code */

    call  compute_totals
    call  compute_grades
    call  create_hist
    call  print_results

    /* end program code */

    popl  %esi		/* Restore ebx, edi, & esi */
    popl  %edi
    popl  %ebx
    movl  %ebp, %esp	/* Destroy stack frame */
    popl  %ebp
    ret			/* Return control to Linux */


compute_totals:
    pushl %ebp		/* Create stack frame */
    movl  %esp, %ebp	/* ebp marks our place in the stack */
    pushl %ebx		/* Save ebx, edi, & esi */
    pushl %edi
    pushl %esi

    /* add your code here... */

    movl $0, %ecx	/* %ecx is used for the count over entries */
    leal scores, %eax

    totals_entry_loop:	/* Loop over the different students/entries */
        cmpl numrec, %ecx /* If current record greater than records */
        jae  totals_exit_entry_loop/* exit loop */

        movl $0, %ebx	/* Set the sum to 0 */

    	/* Add the grades to the sum */
        addw SCORE1(%eax), %bx
        addw SCORE2(%eax), %bx 
        addw SCORE3(%eax), %bx 
        addw SCORE4(%eax), %bx 
        addw SCORE5(%eax), %bx 

	/* Store the sum */
        movw %bx, TOTAL(%eax)

        inc %ecx
	addl $REC_SIZE, %eax
        jmp totals_entry_loop


    totals_exit_entry_loop: /* End Student Loop */


    popl  %esi		/* Restore ebx, edi, & esi */
    popl  %edi
    popl  %ebx
    movl  %ebp, %esp	/* Destroy stack frame */
    popl  %ebp
    ret			/* Return control to parent function */


compute_grades:
    pushl %ebp		/* Create stack frame */
    movl  %esp, %ebp	/* ebp marks our place in the stack */
    pushl %ebx		/* Save ebx, edi, & esi */
    pushl %edi
    pushl %esi

    /* add your code here... */

    movl $0, %ecx	/* %ecx is used for the count over entries */
    leal scores, %eax	/* %eax is used as the current row pointer */

    grades_entry_loop:	/* Loop over the different students/entries */
        cmpl numrec, %ecx /* If current record greater than records */
        jae  grades_exit_entry_loop /* exit loop */

	movl $0, %ebx	/* Clear register for easier debugging */
        movw TOTAL(%eax), %bx /* Set the sum to 0 */

        cmpw $MINA, %bx
        jae grade_a

        cmpw $MINB, %bx
        jae grade_b

        cmpw $MINC, %bx
        jae grade_c

        cmpw $MIND, %bx
        jae grade_d

        movw $'F', GRADE(%eax)
        jmp grades_end_entry_loop

        grade_d:
            movw $'D', GRADE(%eax)
            jmp grades_end_entry_loop

        grade_c:
            movw $'C', GRADE(%eax)
            jmp grades_end_entry_loop

        grade_b:
            movw $'B', GRADE(%eax)
            jmp grades_end_entry_loop

        grade_a:
            movw $'A', GRADE(%eax)
            jmp grades_end_entry_loop

    grades_end_entry_loop:
        addl $REC_SIZE, %eax
        inc %ecx
        jmp grades_entry_loop

    grades_exit_entry_loop: /* End Student Loop */


    popl  %esi		/* Restore ebx, edi, & esi */
    popl  %edi
    popl  %ebx
    movl  %ebp, %esp	/* Destroy stack frame */
    popl  %ebp
    ret			/* Return control to parent function */


create_hist:
    pushl %ebp		/* Create stack frame */
    movl  %esp, %ebp	/* ebp marks our place in the stack */
    pushl %ebx		/* Save ebx, edi, & esi */
    pushl %edi
    pushl %esi

    /* add your code here... */
    
    /* eax - holds the pointer to the current entry */
    /* ecx - holds the counter for the number of the entry */
    movl $scores, %eax
    movl numrec(,1), %ecx
    hist_entry_loop:

        /* edi - holds the current total      */
        movw TOTAL(%eax,1), %di
        /* esi - holds the pointer for scores */
	leal score_ranges, %esi

        scores_loop:
            cmpw 2(%esi), %di
            ja iter_scores_loop

            /* Score is in range */
            subl $score_ranges, %esi /* subtract out the address */
            shrl $2, %esi /* divide count by 4 to get the actual count */
            addw $1, num_scores(%esi)
            jmp exit_scores_loop

        iter_early_loop:
            addl $1, %esi
        iter_scores_loop:
            addl $4, %esi
            jmp scores_loop
        exit_scores_loop:

        /* Decide the grade */
        leal num_grades, %esi

        cmpw $MINA, %di
        jae hist_grade_a

        cmpw $MINB, %di
        jae hist_grade_b

        cmpw $MINC, %di
        jae hist_grade_c

        cmpw $MIND, %di
        jae hist_grade_d

        addl $1, (%esi)
        jmp end_hist_grade

        hist_grade_d:
            addl $1, 1(%esi)
            jmp end_hist_grade

        hist_grade_c:
            addl $1, 2(%esi)
            jmp end_hist_grade

        hist_grade_b:
            addl $1, 3(%esi)
            jmp end_hist_grade

        hist_grade_a:
            addl $1, 4(%esi)
            jmp end_hist_grade

        end_hist_grade:


        addl $REC_SIZE, %eax
    loop hist_entry_loop



    popl  %esi		/* Restore ebx, edi, & esi */
    popl  %edi
    popl  %ebx
    movl  %ebp, %esp	/* Destroy stack frame */
    popl  %ebp
    ret			/* Return control to parent function */


print_results:
    pushl %ebp		/* Create stack frame */
    movl  %esp, %ebp	/* ebp marks our place in the stack */
    pushl %ebx		/* Save ebx, edi, & esi */
    pushl %edi
    pushl %esi

    /* print score histogram */
    call  print_score_hist

    leal  end_of_line, %edi
    pushl %edi		/* print a blank line */
    call  printf
    addl  $4, %esp

    /* print grade histogram */
    call  print_grade_hist

    popl  %esi		/* Restore ebx, edi, & esi */
    popl  %edi
    popl  %ebx
    movl  %ebp, %esp	/* Destroy stack frame */
    popl  %ebp
    ret			/* Return control to parent function */


print_score_hist:
    pushl %ebp		/* Create stack frame */
    movl  %esp, %ebp	/* ebp marks our place in the stack */
    pushl %ebx		/* Save ebx, edi, & esi */
    pushl %edi
    pushl %esi

/*
 * the following commented code will display all the list of scores
 *
 *   movl  numrec(,1), %ecx
 *   movl  $scores, %ebx

 * loop_i:
 *   movl  $0, %eax
 *   movw  TOTAL(%ebx), %ax

 *   pushl %ecx
 *   pushl %ebx
 *   pushl %eax
 *   leal  dummy_str, %edi
 *   pushl %edi
 *   call  printf
 *   addl  $8, %esp
 *   popl  %ebx
 *   popl  %ecx

  *  addl  $REC_SIZE, %ebx
  *  loop  loop_i
*/

    /* loop over all 10 score ranges */
    movl  $10, %ecx
    leal  score_ranges, %esi

  loop_score_hist:

    movl  $0, %eax		/* Get min and max values in this score range */
    movw  (%esi), %ax
    movl  $0, %ebx
    movw  2(%esi), %bx

    /* print score range */
    pushl %esi			/* Save esi & ecx */
    pushl %ecx
    pushl %ebx
    pushl %eax
    leal  score_hist_str, %edi
    pushl %edi
    call  printf
    addl  $12, %esp
    popl  %ecx
    popl  %esi

    pushl %ecx			/* Save ecx */
    movl  $10, %edi		/* Use 10-ecx as index into num_scores */
    subl  %ecx, %edi
    movb  num_scores(%edi), %cl	/* get number of scores in current range */
    andl  $0x000000ff, %ecx
    jz    no_stars		/* don't loop if not printing any stars */

      loop_rec_totals:
	/* print one star */
	pushl %ecx		/* Save ecx & esi */
	pushl %esi
	leal  star_str, %edi
	pushl %edi
	call  printf
	addl  $4, %esp
	popl  %esi		/* Restore ecx & esi */
	popl  %ecx

	loop  loop_rec_totals

  no_stars:
    /* print end of line (i.e. move cursor to beginning of next line) */
    pushl %esi			/* Save esi */
    leal  end_of_line, %edi
    pushl %edi
    call  printf
    addl  $4, %esp
    popl  %esi			/* Restore esi */

    popl  %ecx			/* Restore ecx */
    addl  $4, %esi
    loop loop_score_hist

    popl  %esi		/* Restore ebx, edi, & esi */
    popl  %edi
    popl  %ebx
    movl  %ebp, %esp	/* Destroy stack frame */
    popl  %ebp
    ret			/* Return control to parent function */


print_grade_hist:
    pushl %ebp		/* Create stack frame */
    movl  %esp, %ebp	/* ebp marks our place in the stack */
    pushl %ebx		/* Save ebx, edi, & esi */
    pushl %edi
    pushl %esi

    /* loop over all 5 possible grades */
    movl  $5, %ecx
    leal  grade_ltr_str, %esi

  loop_grade_hist:

    movl  %ecx, %edi			/* Use ecx-1 as index into num_grades */
    decl  %edi
    movb  num_grades(%edi), %al		/* number records with this grade */
    andl  $0x000000ff, %eax

    /* print number of students getting this letter grade */
    pushl %ecx			/* Save ecx & esi */
    pushl %esi
    pushl %eax
    pushl %esi
    leal  grade_hist_str, %edi
    pushl %edi
    call  printf
    addl  $12, %esp
    popl  %esi			/* Restore ecx & esi */
    popl  %ecx

    addl  $2, %esi
    loop  loop_grade_hist

    popl  %esi		/* Restore ebx, edi, & esi */
    popl  %edi
    popl  %ebx
    movl  %ebp, %esp	/* Destroy stack frame */
    popl  %ebp
    ret			/* Return control to Linux */


.section .data		/* initialized data */

    /* Include given data file */

.include "test2.dat"

    /* Declare other initialized variables here */

num_scores:
	.byte	0, 0, 0, 0, 0, 0, 0, 0, 0, 0
num_grades:
	.byte	0, 0, 0, 0, 0

score_ranges:
	.short	0, 50
	.short	51, 100
	.short	101, 150
	.short	151, 200
	.short	201, 250
	.short	251, 300
	.short	301, 350
	.short	351, 400
	.short	401, 450
	.short	451, 500

score_hist_str:
	.string	"%3d - %3d: "
star_str:
	.string	"*"
end_of_line:
	.string "\n"
grade_ltr_str:
	.string	"A", "B", "C", "D", "F"
grade_hist_str:
	.string	"Number of %s's:  %d\n"


  dummy_str:
 	.string	"%d\n"
 

.section .bss		/* uninitialized data */

    /* Declare uninitialized variables here */


